package helper

import (
	"context"
	"encoding/json"
	"io"
	"math"
	"net/http"
	"os"
	"path"
	"time"

	"github.com/duke-git/lancet/v2/cryptor"
	"github.com/duke-git/lancet/v2/fileutil"
	"github.com/golang-jwt/jwt/v4"
	"github.com/jinzhu/copier"
	"github.com/zeromicro/go-zero/core/timex"
)

// GetJwtToken 生成jwt token
func GetJwtToken(secretKey string, seconds, uid int64) (string, error) {
	iat := time.Now().Unix()
	claims := make(jwt.MapClaims)
	claims["exp"] = iat + seconds
	claims["iat"] = iat
	claims["userId"] = uid
	token := jwt.New(jwt.SigningMethodHS256)
	token.Claims = claims
	return token.SignedString([]byte(secretKey))
}

// GetUid 从jwt中获取uid
func GetUid(ctx context.Context) int64 {
	uid, err := ctx.Value("userId").(json.Number).Int64()
	if err != nil {
		return 0
	}
	return uid
}

// Md5 给字符串加盐并多次md5
func Md5(pwd, salt string, times int) string {
	for i := 0; i < times; i++ {
		pwd = cryptor.Md5String(pwd + salt)
	}
	return pwd
}

// CheckPwd 检测是字符串是否是加盐并多次md5生成的
func CheckPwd(source, pwd, salt string, times int) bool {
	return source == Md5(pwd, salt, times)
}

// Copy 从一种结构复制到另一种结构
func Copy(to, from interface{}) error {
	return copier.Copy(to, from)
}

// Paginate 计算分页数据
func Paginate(count int64, page, limit int) (current, last, offset int) {
	current = 1

	if count < 1 {
		return
	}
	last = int(math.Ceil(float64(count) / float64(limit)))
	current = int(page)
	offset = (current - 1) * limit
	return
}

// Upload 上传文件
func Upload(r *http.Request, name, tmpPath string, maxSize int64) (filename string, err error) {
	err = r.ParseMultipartForm(maxSize)
	if err != nil {
		return
	}

	file, handler, err := r.FormFile(name)
	if err != nil {
		return
	}
	defer file.Close()
	if !fileutil.IsDir(tmpPath) {
		err = os.MkdirAll(tmpPath, os.ModePerm)
		if err != nil {
			return
		}
	}
	f := Md5(timex.Now().String(), "", 1) + path.Ext(handler.Filename)
	filename = path.Join(tmpPath, f)
	tempFile, err := os.Create(filename)
	if err != nil {
		return
	}
	defer tempFile.Close()
	io.Copy(tempFile, file)

	return
}

// IsDir 是否目录
func IsDir(path string) bool {
	file, err := os.Stat(path)
	if err == nil {
		return file.IsDir()
	}
	return false
}

// IsFile 是否文件
func IsFile(path string) bool {
	file, err := os.Stat(path)
	if err == nil {
		return !file.IsDir()
	}
	return false
}

func AllFile(path string) (files []string, err error) {
	files = []string{}
	if !IsDir(path) {
		return
	}

	fs, err := os.ReadDir(path)
	if err != nil {
		return
	}

	fsLen := len(fs)
	if fsLen == 0 {
		return
	}

	for i := 0; i < fsLen; i++ {
		if !fs[i].IsDir() {
			files = append(files, fs[i].Name())
		}
	}

	return
}
